#include <linux/module.h>

#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/platform_device.h>
#include <linux/of.h>

#include "led_resource.h"
#include "led_opr.h"
#include "my_led_drv.h"
#include <linux/io.h>

static int g_ledpins[100];
static int g_ledcnt = 0;

// LED2的引脚为GPIO5_3
// IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 地址：0x02290000 + 0x14
static volatile int* IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3;
// GPIO5_GDIR 地址：0x020AC004
static volatile int* GPIO5_GDIR;
//GPIO5_DR 地址：0x020AC000
static volatile int* GPIO5_DR;


// led真初始化函数
static int board_demo_led_init(int which) // 初始化led几，which就是几
{
	printk("init gpio: group %d, pin %d\n", GROUP(g_ledpins[which]), PIN(g_ledpins[which]));
	switch (GROUP(g_ledpins[which]))
	{
		case 0:
		{
			
			printk("init pin of group 0 ...\n");
			break;
		}
		case 1:
		{
			printk("init pin of group 1 ...\n");
			break;
		}
		case 2:
		{
			printk("init pin of group 2 ...\n");
			break;
		}
		case 5: // 这里需要再判断是不是第五组的第三根引脚，这里暂时没有写，所以不管设备树里指定的是哪根引脚初始化的都是第3根
		{
			// IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 地址：0x02290000 + 0x14
			IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 = ioremap(0x02290000 + 0x14, 4);
			// GPIO5_GDIR 地址：0x020AC004
			GPIO5_GDIR = ioremap(0x020AC004, 4);
			//GPIO5_DR 地址：0x020AC000
			GPIO5_DR =  ioremap(0x020AC000, 4);
			printk("init pin of group 3 ...\n");
			break;
		}
	}


	return 0;
}

// led真控制函数
static int board_demo_led_ctl(int which, char status) // 控制led亮灭，led几，which就是几;status为1就是亮，0就是灭
{
	printk("set led %s : group %d, pin %d\n", status ? "on" : "off", GROUP(g_ledpins[which]), PIN(g_ledpins[which]));

	switch (GROUP(g_ledpins[which]))
	{
		case 0:
		{
			printk("set pin of group 0 ...\n");
            break;
		}
		case 1:
		{
			printk("set pin of group 1 ...\n");
            break;
		}
		case 2:
		{
			printk("set pin of group 2 ...\n");
            break;
		}
		case 5: // 这里需要再判断是不是第五组的第三根引脚，这里暂时没有写，所以不管设备树里指定的是哪根引脚控制的都是第3根
		{
			if (status == 1)
			{
				// 点灯
				*GPIO5_DR &= ~(1<<3);
			}
			else if (status == 0)
			{
				// 熄灯
				*GPIO5_DR |= (1<<3);
			}
			
			printk("set pin of group 3 ...\n");
            break;
		}
	}

	return 0;
}

// static int board_demo_get_pin(int which)
// {
// 	return g_ledpins[which];
// }

// static int board_demo_get_cnt(void)
// {
// 	return g_ledcnt;
// }

// 把初始化、控制函数告诉自己定义的led_operations结构体
static struct led_operations board_demo_led_opr = {
	.init		= board_demo_led_init,
    .ctl		= board_demo_led_ctl,
    // .get_pin	= board_demo_get_pin,
    // .get_cnt	= board_demo_get_cnt,
};

// 返回一个指向board_demo_led_opr的指针
struct led_operations* get_board_demo_led_opr(void)
{
	return &board_demo_led_opr;
}


/*-------------------------------------------------------------------*/

// 当设备和驱动匹配成功时调用，用于初始化设备
static int chip_demo_gpio_probe(struct platform_device *pdev)
{
	struct device_node *np;
	int err = 0;
	int led_pin;

	np = pdev->dev.of_node;
	if(!np)
	{
		return -1;
	}

	err = of_property_read_u32(np, "pin", &led_pin);

	g_ledpins[g_ledcnt] = led_pin;
	led_class_create_device(g_ledcnt);
	g_ledcnt++;

	return 0;
}

// 当设备被卸载时调用，用于释放资源
static int chip_demo_gpio_remove(struct platform_device *pdev)
{
	struct device_node *np;
	int err = 0;
	int led_pin;
	int i = 0;

	np = pdev->dev.of_node;
	if(!np)
	{
		return -1;
	}

	err = of_property_read_u32(np, "pin", &led_pin);

	for(i = 0; i < g_ledcnt; i++)
	{
		if (g_ledpins[i] == led_pin)
		{
			led_class_destroy_device(i);
			g_ledpins[i] = -1;
			break;
		}
	}

	for(i = 0; i < g_ledcnt; i++)
	{
		 if (g_ledpins[i] != -1)
            break;
	}

	if (i == g_ledcnt)
		g_ledcnt = 0;

	return 0;
}

// 与设备树的compatible属性匹配的表
static const struct of_device_id my_leds[] = {
	{ .compatible = "my_led,drv" },
	{ }, // 告诉内核这个匹配表到此为止了，不要再往后读了
};

// 定义平台驱动结构体
static struct platform_driver chip_demo_gpio_driver = {
	.probe = chip_demo_gpio_probe,
	.remove = chip_demo_gpio_remove,
	.driver = {
		.name = "my_leds",
		.of_match_table = my_leds,
	},
};

/*---------------------------------------------------------------*/

// 入口函数
static int __init chip_demo_gpio_drv_init(void)
{
	int err;

	err = platform_driver_register(&chip_demo_gpio_driver);
	register_led_operations(&board_demo_led_opr);

	return 0;
}


// 出口函数
static void __exit lchip_demo_gpio_drv_exit(void)
{
	platform_driver_unregister(&chip_demo_gpio_driver);
}

// 其他完善
module_init(chip_demo_gpio_drv_init);
module_exit(lchip_demo_gpio_drv_exit);
MODULE_LICENSE("GPL");







